本篇主旨:透過babel轉譯使用Async function的js檔,使其可在瀏覽器(非Node環境)運行
上篇
閱前注意:
本篇為個人使用筆記,為供未來使用,會包含一些瑣碎的設定
新手發文,還請多多包涵並給予指教
流程為個人嘗試以及思考的脈絡,未必是最佳化的流程
regeneratorRuntime
var asyncFunc = /*#__PURE__*/function () {
//regeneratorRuntime在這!
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function asyncFunc() {
return _ref.apply(this, arguments);
};
}();
遍尋上下文,確實找不到regeneratorRuntime
在哪定義,唯一合理的解釋,只有regeneratorRuntime
是被定義在其他地方而在這裡使用。
我們打開官方文件,搜索一番,發現:
The @babel/polyfill module includes core-js and a custom regenerator runtime to emulate a full ES2015+ environment.
原來,babel在轉譯一些太新的特性時,會產生一些額外的"引用",這些引用存在於@babel/polyfill
裡,regeneratorRuntime
便是其中之一。
這意味著,在你編譯後的檔案中必須包含對@babel/polyfill
的引用。
我們順著官方文件往下看,找找該如何引入@babel/polyfill
,然而我們發現:
? As of Babel 7.4.0, this package has been deprecated in favor of directly including core-js/stable (to polyfill ECMAScript features) and regenerator-runtime/runtime (needed to use transpiled generator functions):
官方並不推這直接引用@babel/polyfill
或core-js/stable
以及regenerator-runtime/runtime
,因為他們太肥了,例如我們只需要regeneratorRuntime
,便不需要整包引入。
對此,官方推薦:
For library/tool authors this may be too much. If you don't need the instance methods like Array.prototype.includes you can do without polluting the global scope altogether by using the transform runtime plugin instead of @babel/polyfill.
打開transform runtime plugin文件,按部就班
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
@babel/plugin-transform-runtime
-用來在轉譯後的js引入Step1所說的額外引入
@babel/runtime
-額外引入的實體檔案,也就是包含regeneratorRuntime
的地方,注意安裝時的參數為--save
沒有-dev
,因為它無論是在測試或正式環境都需要被參考我們需要加入plugins
設定轉譯時使用的plugins
{
"presets": ["@babel/env"],
//加入以下設定,轉譯時會使用@babel/plugin-transform-runtime
"plugins": [
[
"@babel/plugin-transform-runtime"
]
]
}
於terminal執行:
npm run trans
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var asyncFunc = /*#__PURE__*/function () {
var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() {
return _regenerator["default"].wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function asyncFunc() {
return _ref.apply(this, arguments);
};
}();
走到這一步,原以為留暗花明又一村,卻是半路殺出程咬金,細心的人可能已經發現了下面的問題
require
,這意味著babel的轉譯是為了在CommonJS中執行,或者說,在Node環境中執行為了達成最終在瀏覽器+ES5的環境下使用babel轉譯過的async function,我們必須解決以下關鍵問題
regeneratorRuntime
regeneratorRuntime
這部分的程式碼注入轉譯後的js
礙於篇幅,請待下回分解